package com.gui.connect;

import com.gui.exceptions.RedisConnectionException;
import com.gui.exceptions.RedisDataException;
import com.gui.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Created by Gui on 2017/7/19.
 */
public class Command implements Closeable {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    private RedisOutputStream output;

    public Command(OutputStream outputStream) {
        if (outputStream == null) {
            throw new IllegalArgumentException("inputStream should not be null.");
        }
        output = new RedisOutputStream(outputStream);
    }

    public void sendCmd(Cmd cmd, String... args) {
        byte[][] bargs = new byte[args.length][];
        for (int i = 0; i < args.length; i ++) {
            if (args[i] == null) {
                throw new RedisDataException("args should not container null.");
            }
            bargs[i] = SafeEncoder.encode(String.valueOf(args[i]));
        }
        this.sendCmd(cmd.raw, bargs);
    }


    public void sendCmd(byte[] cmd, byte[]... args) {
        try {
            output.write(ReplyType.MULTI.value);
            output.writeAsciiCRLF(String.valueOf(args.length + 1));
            output.write(ReplyType.BULK.value);
            output.writeAsciiCRLF(String.valueOf(cmd.length));
            output.write(cmd);
            output.writeCRLF();

            for (int i = 0; i < args.length; i ++) {
                output.write(ReplyType.BULK.value);
                output.writeAsciiCRLF(String.valueOf(args[i].length));
                output.write(args[i]);
                output.writeCRLF();
            }
            output.flush();
        } catch (IOException e) {
            logger.error(e.toString());
            throw new RedisConnectionException(e);
        }
    }

    public void sendBytes(byte[] data) {
        this.sendBytes(data, 0, data.length);
    }

    public void sendBytes(byte[] data, int offset, int len) {
        try {
            output.write(data, offset, len);
            output.flush();
        } catch (IOException e) {
            throw new RedisConnectionException(e);
        }
    }

    public void sendBytesCRLF(byte[] data) {
        this.sendBytesCRLF(data, 0, data.length);
    }

    public void sendBytesCRLF(byte[] data, int offset, int len) {
        try {
            output.write(data, offset, len);
            output.writeCRLF();
            output.flush();
        } catch (IOException e) {
            throw new RedisConnectionException(e);
        }
    }

    @Override
    public void close() throws IOException {
        if (this.output != null) {
            output.close();
        }
    }
}
